package clue.editor;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import objects.BoardData;
import utils.AutoDealer;

public class ClueMenu extends JMenuBar {

	private static final long serialVersionUID = 1L;
	private JMenuItem undo;
	private JMenuItem redo;
	
	/**
	 * Clue menu ctor
	 */
	public ClueMenu() {

		JMenu fileMenu = new JMenu("File");

		JMenuItem saveFile = new JMenuItem("Save file");

		JMenuItem loadFile = new JMenuItem("Load file");

		JMenuItem newBoard = new JMenuItem("New board");
		
		saveFile.addActionListener(getSaveActionListener());

		loadFile.addActionListener(getLoadActionListener());
		
		newBoard.addActionListener(getNewBoardAction());
		
		JMenu editMenu = new JMenu("Edit");
		
		JMenuItem clearCards = new JMenuItem("Clear");

		undo = new JMenuItem("Undo");

		redo = new JMenuItem("Redo");
		
		JMenuItem autoDeal = new JMenuItem("Auto Deal");
		
		redo.setEnabled(false);
		undo.setEnabled(false);
		
		undo.addActionListener(getUndoAction());
		redo.addActionListener(getRedoAction());
		clearCards.addActionListener(getClearAction());
		autoDeal.addActionListener(getAutoDealListener());
		
		editMenu.add(clearCards);
		editMenu.add(undo);
		editMenu.add(redo);
		editMenu.add(autoDeal);
		
		fileMenu.add(newBoard);
		fileMenu.add(saveFile);
		fileMenu.add(loadFile);
		
		add(fileMenu);
		add(editMenu);
	}

	/**
	 * The method invoked when the user presses auto deal
	 * @return
	 */
	private ActionListener getAutoDealListener()
	{
		return new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {

				// Get the current board data
				BoardData boardData = BoardDataParser.parseFrameToBoardData();
				
				if (boardData.getPlayers() != null && boardData.getPlayers().size() > 0)
				{
					// Deal cards using board data
					AutoDealer.Deal(boardData);
					
					// Modify the frame using the board data
					BoardDataParser.parseBoardDataToFrame(boardData);
					ClueFrame.getInstance().addEdit();
				}
			}
		};
		
		
	}
	
	/**
	 * The method invoked when the user presses save
	 */
	private ActionListener getSaveActionListener() {
		
		return new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {

				BoardDataParser.parseFrameToBoardData();
				boolean isValid = FileHandler.saveFile();
				
				if (isValid)
				{
					GlobalHistory.getInstance().resetHistory();
					undo.setEnabled(false);
					redo.setEnabled(false);
				}
			}
		};
	}
	
	/**
	 * The method invoked when the user press load 
	 * @return
	 */
	private ActionListener getLoadActionListener() {
		
		return new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {

				int choice = JOptionPane.OK_OPTION;
				
				// Check if there were any changes
				if (GlobalHistory.getInstance().isUndoable())
				{
					choice = JOptionPane.showConfirmDialog(ClueFrame.getInstance(), "You have done changes. All changes will be lost! do you want to continue?");
				}
				
				// There are no changes or the user choice was to ignore the changes
				if (choice == JOptionPane.OK_OPTION)
				{
					// Load the xml and update history accordingly
					BoardData boardData = FileHandler.loadXmlFile();
					
					if (boardData != null)
					{
						ClueFrame.getInstance().getPlayersPanel().removeAllPlayers();
						GlobalHistory.getInstance().resetHistory();
						undo.setEnabled(false);
						redo.setEnabled(false);
						BoardDataParser.parseBoardDataToFrame(boardData);
						
						GlobalHistory.getInstance().resetHistory();
						
						GlobalHistory.getInstance().initHistory(boardData);
					}
				}
				
				
			}
		};
	}
	
	/**
	 * The method invoked when the user press clear
	 */
	private ActionListener getClearAction() {
		return new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {

				// Clear all the cards 
				GlobalHistory.getInstance().setDisabled(true);
				clearAllPlayerCards();
				GlobalHistory.getInstance().setDisabled(false);
				ClueFrame.getInstance().addEdit();			}
		};
	}
	
	/**
	 * The method clears all the cards of all the players
	 */
	private void clearAllPlayerCards()
	{
		for (Component component : ClueFrame.getInstance().getPlayersPanel().getPlayersInnerPanel().getComponents()) {
			if (component instanceof PlayerPanel)
			{
				((PlayerPanel) component).clearCardSelection();
				validate();
				repaint();
			}
		}
	}
	
	/**
	 * The method invoked when the user press new board
	 */
	private ActionListener getNewBoardAction() {
		return new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				int choice = JOptionPane.OK_OPTION;
				
				// Check if changes were made
				if (GlobalHistory.getInstance().isUndoable())
				{
					choice = JOptionPane.showConfirmDialog(ClueFrame.getInstance(), "You have done changes. All changes will be lost! do you want to continue?");
				}
				
				// If there are no changes or the user decided to ignore them
				if (choice == JOptionPane.OK_OPTION)
				{
					// Remove all players and reset the history
					ClueFrame.getInstance().getPlayersPanel().removeAllPlayers();
					ClueFrame.getInstance().getBoardPanel().getEnvelopePanel().resetEnvelope();
					GlobalHistory.getInstance().resetHistory();
					undo.setEnabled(false);
					redo.setEnabled(false);
				}
			}
		};
	}
	
	/**
	 * The method invoked when the user presses undo
	 */
	private ActionListener getUndoAction() {
		return new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				// Perform undo using undo manager
				ClueFrame.getInstance().getUndoManager().performUndo();
			
				// If after undo the state is not undoable set undo disabled
				if (!GlobalHistory.getInstance().isUndoable())
				{
					undo.setEnabled(false);
					
				}
				
				// If after undo the state is redoable set redo enabled
				if (GlobalHistory.getInstance().isRedoable())
				{
					redo.setEnabled(true);
				}
				
				validate();
				repaint();
			}
		};
	}
	
	/**
	 * The method invoked when the user presses redo
	 */
	private ActionListener getRedoAction() {
		return new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				// Perform redo using undo manager
				ClueFrame.getInstance().getUndoManager().performRedo();

				// If after redo the state is undoable set undo enabled
				if (GlobalHistory.getInstance().isUndoable())
				{
					undo.setEnabled(true);
					
				}
				
				// If after redo the state is not redoable set redo disabled
				if (!GlobalHistory.getInstance().isRedoable())
				{
					redo.setEnabled(false);
				}
				
				validate();
				repaint();
				
				
			}
		};
	}

	public JMenuItem getRedo() {
		return redo;
	}

	public JMenuItem getUndo() {
		return undo;
	}
	
}
